Bootloader 与 OTA 升级设计要点
本专题综合 07-通信协议与升级 板块约 20 篇 Bootloader/OTA/固件加密问答提炼而成,是星球该话题的高频问题全景图。
一、为什么标志位必须由 Bootloader 来写
学员问:OTA 升级标志位,App 里不能自己刷 Flash 写吗?答案从安全架构出发:信任锚和信任根由 Bootloader 掌握,App 本身是被验证的对象。如果允许 App 修改"可信标志位",恶意程序就能打断信任链。所以正确流程是:App 下载完固件后只置"已下载完成"标志,由 Bootloader 校验完整性与可信性之后,才由它去写"可以启动"的标志。App 说的是"下载好了",不等于"可以启动"。OTA,一定要bootloader负责刷写flash更新标志位(盛夏的时光 / Jack)
信任链更底层的追问是:芯片上电先跑厂商 BootROM,再跳到用户 Bootloader,这段信任链怎么建立?答案是 BootROM 与启动地址由芯片硬件固化、不可修改,启动地址固定(如 0x08000000),这就是整条链的锚点。老师,再请教一个问题。bootloader启动app会对app进行验签(Jack)
二、Flash 分区设计的工程细节
STM32F407 内部 Flash OTA 分区(无外挂 Flash 场景)的讨论给出了几条硬知识:
- STM32 按扇区擦除,配置参数区优先用最小 16KB 扇区,且做 A/B 双备份;
- 升级标志/flag 是频繁改变的数据,不要放进 64KB 大扇区——每次改 flag 都要擦整片,擦写时间长且伤寿命;flag 应放小扇区,甚至可以和 Config 共用一套 A/B 区;
- 固件头、版本、CRC 等校验信息单独给小区即可。Jack哥我有一个问题,我这边有一个项目需要用到STM32F407ZET6或者是ST(Jack)
升级标志为何由 Boot 掌握(信任链视角)见上文;多板系统(主板 + 扩展板)的分工是:主板升自己 → 放主板 Boot;主板升扩展板 → 放主板 App,Boot 保持精简。老师,我想请问一个场景,现在有三块板子,一块主板,两块扩展板(Jack)
三、跳转的三大经典坑
星球问答里 Bootloader 跳转 APP 的高频故障集中在三处,BootLoader 程序问题(Jack)做了汇总:
- CubeMX 生成的时钟初始化卡死:
HAL_RCC_OscConfig等待标志位前缺少延时/超时处理,失败后进入空的Error_Handler死循环; - 跳转后 APP 不跑:没有重设中断向量表——修改
SCB->VTOR(VECT_TAB_OFFSET)为 APP 的偏移量; - 跳转后卡在中断里:Bootloader 用过的外设与中断没有反初始化、标志位没有清除;若 Bootloader 用了 systick,跳转前必须关闭。补充:Bootloader 内有 FreeRTOS 时,跳转前要关 systick 定器和全局中断,APP 侧先反向初始化再初始化外设与时钟。Bootloader跳转APP时需要注意什么(Jack)
关于栈:跳转时设置的 APP 栈顶指针比 Bootloader 的低一点,会不会永久浪费 SRAM?不会——Bootloader 仅启动时运行,APP 启动文件会把 MSP 重新指向 SRAM 最高地址,覆盖 Bootloader 的栈;那段"脏数据"可被覆写。老师,在BootLoader跳转函数中会设置app的栈顶指针(Jack)
boot 引脚与启动模式的关系:上电后厂商 BootROM 根据 BOOT0/BOOT1 电平选择启动区域,Flash 起始处放的是你的 Bootloader,再由它跳 APP。老师,上电的时候,boot引脚选择 user flash启动(Jack)
工具链选择上有个反直觉的点:写 Bootloader 反而需要标准库(或寄存器操作),因为它要最小化依赖、精确控制初始化过程;为什么写Bootloader需要使用标准库(Jack)HAL 与标准库在企业中长期并存,ST 已停止维护标准库,但存量项目与 Bootloader 场景仍在用。老师,课程都是教HAL库嘛?但是开发中不是标准库用的多一点嘛?一些老一点的项目(Jack)
四、安全防线:加密、验签与防回滚
这是星球讨论最密集的子话题,核心结论可以归纳成四条:
- AES 加密防不了工厂,防得了用户。生产阶段工厂同时拿到 Bootloader 与加密的 App,密钥与解密逻辑同在,等于没加密;它的价值是防范出厂后的客户与拆解者。老师,对于Bootloader中仅仅使用AES解密APP中的固件(Jack)
- 片上 Flash 存密钥不是绝对安全。即使设置了读保护,高成本攻击仍可能读出;真正值钱的固件(如医疗/工业高端设备)会用带安全引擎的特供芯片或外部安全芯片(HSM):把明文交给 HSM 加密后回传。关于固件加密的相关提问: 提(Lili_iliLX / Jack)行业内单片机加密是怎么做的:(Jack)为什么要用硬件加密芯片? 以(Jack)
- 防工厂超额生产的三个方案:下载工具读芯片 UUID 作为盐生成绑定固件并上云跟踪;每台设备证书/密钥对写入 OTP,Boot 启动验签;Bootloader 与整机分别交给不同供应商生产,Boot 内做混淆、防篡改、反调试。老师,对于Bootloader中仅仅使用AES解密APP中的固件(Jack)
- CRC 不能当安全校验用。CRC 只防误码,不防恶意篡改——攻击者改完固件可以连 CRC 一起重算;完整性校验要走签名(哈希 + 非对称验签)。为什么不能用CRC校验固件(Jack)
OTA 还要防降级攻击(刷入有漏洞的旧固件),这需要版本号/防回滚计数器参与验签。嵌入式OTA其中一个问题,别人可能刷入旧固件攻击你(Jack)量产发布的工程实践:构建时用 CMake 调 Python 脚本做 MD5 并自动打包。如果是在实际生产当中是自己进行文件加密再发(Jack)
车规做法更进一步:eFuse/OTP 存密钥 + BootROM 解密 + XIP 硬件解密引擎,CPU 全程不见密文。在汽车领域这种MCU芯片很常见(OR i / Jack)
五、传输层与升级策略
- 传输协议放在中间件层而不是 BSP:BSP 只负责把串口/CAN 收到的原始组包数据放进缓冲区,解析交给 Ymodem/Modbus 等中间件——因为"串口上能走的协议穷不尽"。问:和硬件强相关的通讯协议或者算法,比如ymodem协议、modbus协议(Jack)
- Ymodem 起始帧中文件名字段长度不固定,文件大小的提取依赖加密/打包工具在固定偏移写入长度信息。Q:老师 这里我有个疑惑,这里是出自OTA升级专题(Jack)
- 只有 CAN 口的板子照样可以做升级:先学 OTA 框架,再把传输层换成 CAN 报文。这个你可以先学习OTA,然后O(Jack)
- AI 已经能"一遍生成"485 双区升级的 Bootloader 和上位机脚本,但量产级产品的价值一半在冗余与 Corner case 处理,AI 生成后仍需全面分析与长稳测试。老师,今天让ai写了一个bootloader程序,一遍生成可以使用(Jack)
六、入门路径建议
星球课程把"标准库版 Bootloader → Ymodem/OTA 升级 → 固件加密验签"作为一条主线项目。对个人学习者,建议的最小闭环是:双区分区 + flag 区设计 → 串口/CAN 收包与组包 → CRC 完整性 → 跳转与向量表重映射 → 再叠加 AES + 签名 + 防回滚。每一步在星球都有对应问答可查(见来源笔记)。
来源笔记
- OTA,一定要bootloader负责刷写flash更新标志位(盛夏的时光 / Jack)
- 老师,再请教一个问题。bootloader启动app会对app进行验签(Jack)
- Jack哥我有一个问题,我这边有一个项目需要用到STM32F407ZET6或者是ST(Jack)
- 老师,我想请问一个场景,现在有三块板子,一块主板,两块扩展板(Jack)
- BootLoader 程序问题(Jack)
- Bootloader跳转APP时需要注意什么(Jack)
- 老师,在BootLoader跳转函数中会设置app的栈顶指针(Jack)
- 老师,上电的时候,boot引脚选择 user flash启动(Jack)
- 为什么写Bootloader需要使用标准库(Jack)
- 老师,课程都是教HAL库嘛?但是开发中不是标准库用的多一点嘛?一些老一点的项目(Jack)
- 老师,对于Bootloader中仅仅使用AES解密APP中的固件(Jack)
- 关于固件加密的相关提问: 提(Lili_iliLX / Jack)
- 行业内单片机加密是怎么做的:(Jack)
- 为什么要用硬件加密芯片? 以(Jack)
- 为什么不能用CRC校验固件(Jack)
- 嵌入式OTA其中一个问题,别人可能刷入旧固件攻击你(Jack)
- 如果是在实际生产当中是自己进行文件加密再发(Jack)
- 在汽车领域这种MCU芯片很常见(OR i / Jack)
- 问:和硬件强相关的通讯协议或者算法,比如ymodem协议、modbus协议(Jack)
- Q:老师 这里我有个疑惑,这里是出自OTA升级专题(Jack)
- 这个你可以先学习OTA,然后O(Jack)
- 老师,今天让ai写了一个bootloader程序,一遍生成可以使用(Jack)
- 老师 我问一下Bootloader的编写为何要关闭RTC和禁用中断(Jack)